package com.neutech.service.impl;

import com.neutech.entity.User;
import com.neutech.enumeration.ResultExceptionEnum;
import com.neutech.mapper.UserMapper;
import com.neutech.service.UserService;
import com.neutech.vo.ResultVO;
import com.neutech.form.UserForm;
import com.neutech.vo.UserVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.TaskExecutor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.Random;

@Service
public class UserServiceImpl implements UserService {

    private final UserMapper mapper;
    private final RedisTemplate<Object, Object> redisTemplate;
    private final JavaMailSender mailSender;
    //private final TaskExecutor taskExecutor;

    @Autowired
    public UserServiceImpl(UserMapper mapper, RedisTemplate<Object, Object> redisTemplate,
                           JavaMailSender mailSender) {
        this.mapper = mapper;
        this.redisTemplate = redisTemplate;
        this.mailSender = mailSender;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultVO<Void> regist(UserForm userForm) {

        Integer userId = userForm.getUserId();
        if (userId != null)
            return ResultVO.error(ResultExceptionEnum.FORMAT_EXCEPTION);

        if (!mapper.isUsernameInUse(userForm.getUsername()).equals(0))
            return ResultVO.error(ResultExceptionEnum.USERNAME_IN_USE);

        if (Boolean.FALSE.equals(redisTemplate.hasKey(userForm.getEmail())))
            return ResultVO.error(ResultExceptionEnum.VERIFY_CODE_NOT_SEND);

        User user = parseFormToUser(userForm);

        user.setRole((byte) 1); //0-管理员 1-用户
        user.setCreateTime(new Date());

        String verifyCode = (String) redisTemplate.boundValueOps(userForm.getEmail()).get();

        if (verifyCode == null || !Objects.equals(verifyCode, userForm.getVerifyCode()))
            return ResultVO.error(ResultExceptionEnum.VERIFY_CODE_WRONG);

        int result = mapper.insertSelective(user);

        if (result == 1) return ResultVO.success();
        else return ResultVO.error(ResultExceptionEnum.UNKNOWN_ERROR_OCCURED);

    }

    @Override
    public ResultVO<UserVO> login(String username, String password) {
        User user = mapper.login(username, password);
        if (user == null) {
            return ResultVO.error(ResultExceptionEnum.LOGIN_NOT_MATCH);
        }
        UserVO userVO = parseUserToVO(user);
        return ResultVO.success(userVO);
    }

    @Override
    public ResultVO<Void> checkUsername(String username) {
        if (mapper.isUsernameInUse(username).equals(0))
            return ResultVO.success();
        return ResultVO.error(ResultExceptionEnum.USERNAME_IN_USE);
    }

    @Override
    public ResultVO<UserVO> changeUserInfo(UserForm userForm) {

        Integer userId = userForm.getUserId();
        if (userId == null) return ResultVO.error(ResultExceptionEnum.FORMAT_EXCEPTION);

        User user = mapper.selectByPrimaryKey(userId);
        if (user == null)
            return ResultVO.error(ResultExceptionEnum.USER_NOT_EXIST);

        user.setId(userForm.getUserId());
        user.setUsername(userForm.getUsername());
        user.setPassword(null);
        user.setEmail(userForm.getEmail());
        String phone = userForm.getPhone();
        if (phone != null)
            user.setPhone(phone);

        user.setUpdateTime(new Date());

        int result = mapper.updateByPrimaryKeySelective(user);

        if (result == 1) return ResultVO.success(parseUserToVO(user));
        else return ResultVO.error(ResultExceptionEnum.UNKNOWN_ERROR_OCCURED);

    }

    @Override
    public ResultVO<Void> sendVerifyMail(String receiver) {
        Random random = new Random(new Date().getTime());
        String verifyCode = String.format("%06d", random.nextInt(1000000));

        SimpleMailMessage smm = new SimpleMailMessage();
        smm.setSubject("验证码");//设置邮件标题
        smm.setText("尊敬的用户,您好:\n"
                + "\n本次请求的邮件验证码为:" + verifyCode + "（请勿泄露此验证码，5分钟后失效）\n"
                + "\n如非本人操作，请忽略该邮件。\n(这是一封自动发送的邮件，请不要直接回复）");
        smm.setFrom("bin_track@163.com");
        smm.setTo(receiver);//收件人
        try {
            mailSender.send(smm);//发送邮件
            redisTemplate.boundValueOps(receiver).set(verifyCode);
            //redisTemplate.boundValueOps(receiver).set(verifyCode, 5, TimeUnit.MINUTES);
            return ResultVO.success();
        } catch (MailException e) {
            e.printStackTrace();
            return ResultVO.error(ResultExceptionEnum.MAIL_FAIL_TO_SEND);
        } catch (Exception e) {
            return ResultVO.error(ResultExceptionEnum.UNKNOWN_ERROR_OCCURED);
        }
    }

    @Override
    public ResultVO<Void> checkPassword(Integer userId, String password) {
        Integer code = mapper.checkPassword(userId, password);
        if (code == null)
            return ResultVO.error(ResultExceptionEnum.LOGIN_NOT_MATCH);
        return ResultVO.success();
    }

    @Override
    public ResultVO<Void> changePassword(Integer userId, String oldPassword, String newPassword) {
        if (oldPassword.equals(newPassword))
            return ResultVO.error(ResultExceptionEnum.PASSWORD_NOT_CHANGED);

        Integer code = mapper.updatePassword(userId, oldPassword, newPassword);
        if (code != 1)
            return ResultVO.error(ResultExceptionEnum.UNKNOWN_ERROR_OCCURED);
        return ResultVO.success();
    }

    private User parseFormToUser(UserForm userForm) {
        User user = new User();

        user.setId(userForm.getUserId());
        user.setUsername(userForm.getUsername());
        user.setPassword(userForm.getPassword());
        user.setEmail(userForm.getEmail());
        user.setPhone(userForm.getPhone());

        return user;
    }

    private UserVO parseUserToVO(User user) {
        UserVO userVO = new UserVO();

        userVO.setId(user.getId());
        userVO.setUsername(user.getUsername());
        userVO.setEmail(user.getEmail());
        userVO.setPhone(user.getPhone());

        return userVO;
    }

}
